import doctest


######################################
# XMLRPC SERVER
######################################


from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler

class SpinyHooks:
    """ quills? """
    def pow(self, x, y):
        return x ** y

    def echo(self,x):
        return x

def runserver(port=6882):
    serveraddr = ('', port)
    srvr = SimpleXMLRPCServer(serveraddr,SimpleXMLRPCRequestHandler)
    srvr.register_instance(SpinyHooks())
    srvr.register_introspection_functions()
    srvr.serve_forever()


print "starting server"
#runserver()
print "server ready"

######################################
# SPINY
######################################

def exactly(thing):
    return thing

def spinymunger(thing,verbose=True):
    """
    replaces source for each example with a call to a spiny invocation
    """
    if not isinstance(thing,str):
        raise ValueError,"cannot munge a non-string"   
    return "spinyinvoke(" + thing.strip() + ")\n" 

class Phony(object):
    """
    coping with doctest; N.B.
    return strings must be sent to stdout, NOT returned
    """
    def __init__(self):
        self.meth = None  
    
    def phony(self):
     
        print '[0, 1, 4, 9, 16]'
        yield(None)
    
        print '[]'
        yield(None)
    
        print "'a'"
        yield(None)
    
    def __call__(self,thing):
        self.meth = self.meth or self.phony()
        return self.meth.next()

spinyinvoke = exactly #no need for much to happen yet 
       
#spinyinvoke = Phony() also works


class SpinyParser(doctest.DocTestParser):
    """
    backward compatible with doctest parser, plus hook for text postprocessing.
    
    set spiny to True for standard spiny processing
    
    alternate processing hook: set spiny to False and write your own munger (no 
    use case planned, but hey, it's free while I'm here)
    
    Strictly speaking this could be done offline, but this is easy enough and 
    more convenient for the instructor.

    """

    def __init__(self,spiny=False,munger=None):
        if spiny:
            munger = spinymunger
        if munger:
            self.munger = munger
        else:
            self.munger = exactly
            
    def get_doctest(self,*args):
        test = doctest.DocTestParser.get_doctest(self,*args)
        for example in test.examples:
            example.source = self.munge(example.source)
        return test

    def munge(self,thing):
        return self.munger(thing)
 